package org.xx.armory.spring5.mvc.captchacode;

import com.google.code.kaptcha.NoiseProducer;
import com.google.code.kaptcha.util.Configurable;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.PathIterator;
import java.awt.image.BufferedImage;
import java.util.Random;

/**
 * 基本的图像噪音生成器。
 *
 * <p>
 * 只包括一条干扰线。
 * </p>
 *
 * @author Haart
 */
public final class SimpleNoise
        extends Configurable
        implements NoiseProducer {
    /**
     * {@inheritDoc}
     */
    @Override
    public void makeNoise(
            BufferedImage image,
            float factorOne,
            float factorTwo,
            float factorThree,
            float factorFour
    ) {
        final Color color = getConfig().getNoiseColor();

        // image size
        final int width = image.getWidth();
        final int height = image.getHeight();

        // the points where the line changes the stroke and direction
        Random rand = new Random();
        int x0 = (int) (width * factorOne);
        int y0 = (int) (height * rand.nextFloat());
        int xc1 = (int) (width * factorTwo);
        int yc1 = (int) (height * rand.nextFloat());
        int xc2 = (int) (width * factorThree);
        int yc2 = (int) (height * rand.nextFloat());
        int x1 = (int) (width * factorFour);
        int y1 = (int) (height * rand.nextFloat());

        // the curve from where the points are taken
        final CubicCurve2D cc = // new CubicCurve2D.Float(10, 80, 60, 30, 110, 130, 160, 80);
                new CubicCurve2D.Float(x0, y0, xc1, yc1, xc2, yc2, x1, y1);

        // creates an iterator to define the boundary of the flattened curve
        final PathIterator pi = cc.getPathIterator(null, 2);

        final Graphics2D graph = (Graphics2D) image.getGraphics();
        try {
            graph.setRenderingHints(new RenderingHints(
                    RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON));

            graph.setColor(color);
            graph.setStroke(new BasicStroke(2F));
            // while pi is iterating the curve, adds points to temporary array
            int xp = (int) cc.getX1();
            int yp = (int) cc.getY1();
            int xn, yn;
            while (!pi.isDone()) {
                float[] coordinates = new float[6];
                switch (pi.currentSegment(coordinates)) {
                    case PathIterator.SEG_MOVETO:
                        xp = (int) coordinates[0];
                        yp = (int) coordinates[1];
                        break;
                    case PathIterator.SEG_LINETO:
                        xn = (int) coordinates[0];
                        yn = (int) coordinates[1];
                        graph.drawLine(xp, yp, xn, yn);
                        xp = xn;
                        yp = yn;
                        break;
                }
                pi.next();
            }
        } finally {
            graph.dispose();
        }
    }
}
